#include "Adafruit_SHT31.h"

/* Includes ------------------------------------------------------------------*/
#include "DEV_Config.h"
#include "EPD.h"
#include "GUI_Paint.h"
#include "imagedata.h"
#include <stdlib.h>
// #include "stdio.h"
// #include "string.h"
// #include "iostream"

#include <Wire.h>
#include "Adafruit_SHT31.h"
#include "RTClib.h"

#include <EEPROM.h>

#include <WiFi.h>


#define debuguse 0  //是否开调试输出


RTC_DATA_ATTR int TimeWakeCount = 0;  //这个参数不会应为休眠而清除


#define NTP1 "ntp1.aliyun.com"
#define NTP2 "ntp2.aliyun.com"
#define NTP3 "ntp3.aliyun.com"

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  60       /* Time ESP32 will go to sleep (in seconds) */


// #define BUTTON_PIN_BITMASK 0x8004 // GPIOs 2 and 15
#define BUTTON_PIN_BITMASK 0xB00001014 // GPIOs 2 and 15

//填写WIFI入网信息
const char *ssid = "WH_HOME";                                                                                // WIFI账户
const char *password = "A19901366";   

RTC_DS3231 rtc;
Adafruit_SHT31 sht31 = Adafruit_SHT31();

UBYTE *BlackImage;




int SetAlarmHour = 0; //读数据，闹钟设置的小时
int SetAlarmMin = 0; //读数据，闹钟设置的分钟
int SetAlarMode = 0; //读数据，闹钟设置的模式  响一次，5天响，7天响  数据为 1/5/7
int SetAlarOnOffFlag = 0; //读数据，闹钟设置的开关  数据为0/1


int button1Flag=0;//Buton1被按下
int button2Flag=0;//Buton2被按下
int button3Flag=0;//Buton3被按下
int button4Flag=0;//Buton4被按下
int button5Flag=0;//Buton5被按下
int button6Flag=0;//Buton6被按下

int AlarmStartFlag=0;//闹钟是否开始响标志

char daysOfTheWeek[7][12] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};

/*
Method to print the reason by which ESP32
has been awaken from sleep
打印唤醒的原因
*/

uint8_t WakeFlag=0;//苏醒的原因


//得到苏醒的原因
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();
  WakeFlag=0;
  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : 
    {
      WakeFlag=1;
      #if debuguse
      Serial.println("Wakeup caused by external signal using RTC_IO"); 
      #endif
    }break;
    case ESP_SLEEP_WAKEUP_EXT1 :
    {
      WakeFlag=2;
      #if debuguse
        Serial.println("Wakeup caused by external signal using RTC_CNTL"); 
      #endif      
    } break;
    case ESP_SLEEP_WAKEUP_TIMER : 
    {
      WakeFlag=3;
      #if debuguse
      Serial.println("Wakeup caused by timer");
      #endif  
     } break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : 
    {
      WakeFlag=4;
      #if debuguse
      Serial.println("Wakeup caused by touchpad"); 
      #endif        
    }break;
    case ESP_SLEEP_WAKEUP_ULP :
    {
       WakeFlag=5;
      #if debuguse
      Serial.println("Wakeup caused by ULP program");     
      #endif      
    }break;
    default : 
    {
      WakeFlag=6;
      #if debuguse
      Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); 
      #endif  
    }break;
  }
}

//打印和设置rtc时间
void printLocalTime()
{

  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    #if    debuguse  
      Serial.println("Failed to obtain time");
    #endif
    return;
   }
  //Serial.print(asctime(&timeInfo)); //默认打印格式：Mon Oct 25 11:13:29 2021
  #if    debuguse  
  Serial.println(&timeinfo, "%A, %Y-%m-%d %H:%M:%S");  
  Serial.println("Get Ntp time is:");
  Serial.println(timeinfo.tm_year);
  Serial.println(timeinfo.tm_mon);
  Serial.println(timeinfo.tm_mday);
  #endif

//设置RTC时间
  rtc.adjust(DateTime(timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec));
}

//电池电量的计算
int PowerVolume(int readAD)
{
  readAD+=180;  
   float  VBat=(33.0/4095.0)*readAD;//得到当前电池电压
  // Serial.println("readAD :");
  // Serial.println(readAD);

  // Serial.println("readAD VBat:");
  // Serial.println(VBat);
  
  if(VBat>4.2) { return 100;}
  else if((VBat<=4.2)&&(VBat>4.06)) { return 100;}
  else if((VBat<=4.06)&&(VBat>3.98))  {return 90;}
  else if((VBat<=3.98)&&(VBat>3.92))  {return 80;}
  else if((VBat<=3.92)&&(VBat>3.87))  {return 70;}
  else if((VBat<=3.87)&&(VBat>3.82))  {return 60;}
  else if((VBat<=3.82)&&(VBat>3.79))  {return 50;}
  else if((VBat<=3.79)&&(VBat>3.77))  {return 40;}
  else if((VBat<=3.77)&&(VBat>3.74))  {return 30;}
  else if((VBat<=3.74)&&(VBat>3.68))  {return 20;}
  else if((VBat<=3.68)&&(VBat>3.45))  {return 10;}
  else if((VBat<=3.45)&&(VBat>3.00))  {return 5;}
  else if((VBat<=3)&&(VBat>2.00))  {return 0;}
  else  {return 0;}
}

//墨水屏的输出
void epdOut()
{
    DateTime now = rtc.now();

    digitalWrite(23, LOW); //打开墨水屏电源
    DEV_Delay_ms(100);

    #if    debuguse
        printf("EPD_2IN9_test Demo\r\n");
    #endif

    DEV_Module_Init();

    #if    debuguse
        printf("e-Paper Init and Clear...\r\n");
    #endif
    EPD_2IN9_Init(EPD_2IN9_FULL);
    EPD_2IN9_Clear();
    //  DEV_Delay_ms(500);


        //Create a new image cache
    UBYTE *BlackImageAll;
    /* you have to edit the startup_stm32fxxx.s file and set a big enough heap size */
    UWORD Imagesize = ((EPD_2IN9_WIDTH % 8 == 0)? (EPD_2IN9_WIDTH / 8 ): (EPD_2IN9_WIDTH / 8 + 1)) * EPD_2IN9_HEIGHT;
    if((BlackImageAll = (UBYTE *)malloc(Imagesize)) == NULL) {
        #if    debuguse      
        printf("Failed to apply for black memory...\r\n");        
        #endif
        while(1);
    }
    #if    debuguse     
    printf("Paint_NewImage\r\n");
    #endif    
     Paint_NewImage(BlackImageAll, EPD_2IN9_WIDTH, EPD_2IN9_HEIGHT, 270, WHITE);//旋转了270度显示

    Paint_SelectImage(BlackImageAll);
    Paint_Clear(WHITE);
    Paint_DrawLine(0, 20, 296, 20, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//上格横线
    Paint_DrawRectangle(210, 20, 296, 108, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);//左边矩形框
    Paint_DrawLine(0, 108, 296, 108, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//下面横线
    Paint_DrawLine(1, 20, 1, 108, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//最左边竖线
    Paint_DrawLine(0, 88, 210, 88, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//中间闹钟横线
    

        //显示时间
    EPD_2IN9_Init(EPD_2IN9_PART);
    Paint_SelectImage(BlackImageAll);
     PAINT_TIME sPaint_time2;
    sPaint_time2.Hour = now.hour();
    sPaint_time2.Min = now.minute();
    sPaint_time2.Sec = now.second();//这个实际不显示

    Paint_ClearWindows(50, 30, 20 + Font48.Width * 7, 30 + Font48.Height, WHITE);
    Paint_DrawTime(50, 30, &sPaint_time2, &Font48, WHITE, BLACK);

//显示当前年月日 星期
    String datatemp1=String(now.year(), DEC);//转换成字符串 显示年
    const char *tempdatastr1 = datatemp1.c_str(); //转换为字符数组
    // Paint_DrawString_EN(0, 0, "2022-09-26", &Font16, WHITE, BLACK);//白底黑字
    Paint_DrawString_EN(0, 2, tempdatastr1 , &Font16, WHITE, BLACK);//白底黑字
    Paint_DrawString_EN(43, 2, "-", &Font16, WHITE, BLACK);//白底黑字

    String datatemp2=String(now.month(), DEC);////转换成字符串 显示月
    const char *tempdatastr2 = datatemp2.c_str(); //转换为字符数组
    Paint_DrawString_EN(53, 2, tempdatastr2, &Font16, WHITE, BLACK);//白底黑字
    Paint_DrawString_EN(73, 2, "-", &Font16, WHITE, BLACK);//白底黑字
    
    String datatemp3=String(now.day(), DEC);//转换成字符串 显示日期
    const char *tempdatastr3 = datatemp3.c_str(); //转换为字符数组
    Paint_DrawString_EN(83, 2, tempdatastr3, &Font16, WHITE, BLACK);//白底黑字

    Paint_DrawString_CN(118, 2,daysOfTheWeek[now.dayOfTheWeek()], &Font12CN, BLACK, WHITE);//显示星期

//    显示电量

    int sensorValue=PowerVolume(analogRead(A0));//gpio 36  
    Paint_DrawString_CN(190, 0,"电量：", &Font12CN, BLACK, WHITE);
    Paint_DrawNum(232, 2, sensorValue, &Font16, BLACK, WHITE);  //电量
    Paint_DrawString_EN(270, 2, "%", &Font16, WHITE, BLACK);//白底黑字

  // //最下格的文字
  //     Paint_DrawString_CN(2, 109,"晴转多云", &Font12CN, BLACK, WHITE);
  //     Paint_DrawString_CN(148, 109,"温度：", &Font12CN, BLACK, WHITE);
  //     Paint_DrawString_EN(194, 109, "30~33", &Font16, WHITE, BLACK);//白底黑字
  //     Paint_DrawString_CN(276, 109,"℃", &Font12CN, BLACK, WHITE);
      
  //中间的闹钟的位置    
  if(SetAlarOnOffFlag==1)  
  {
    Paint_DrawString_CN(2, 88,"闹钟开", &Font12CN, BLACK, WHITE);    
  }
  else 
  {
  Paint_DrawString_CN(2, 88,"闹钟关", &Font12CN, BLACK, WHITE);
  }  

  if(SetAlarMode==1)    
  {
      Paint_DrawString_CN(68, 88,"一次", &Font12CN, BLACK, WHITE);
  }
  else if(SetAlarMode==5)    
  {
      Paint_DrawString_CN(68, 88,"五天模式", &Font12CN, BLACK, WHITE);
  }
  else if(SetAlarMode==7)    
  {
      Paint_DrawString_CN(68, 88,"七天模式", &Font12CN, BLACK, WHITE);  
  }

    //显示设定的闹钟时间    
    PAINT_TIME sPaint_alar_time2;
    sPaint_alar_time2.Hour = SetAlarmHour;
    sPaint_alar_time2.Min = SetAlarmMin;
    sPaint_alar_time2.Sec = 0;//这个实际不显示  
    Paint_ClearWindows(140, 90, 30 + Font16.Width * 7, 88 + Font16.Height, WHITE);
    Paint_DrawTime(140, 90, &sPaint_alar_time2, &Font16, WHITE, BLACK);

  // Paint_DrawString_EN(148, 88, "07:10", &Font16, WHITE, BLACK);//白底黑字
        
//温度、湿度和大气压
    float t = sht31.readTemperature();
    float h = sht31.readHumidity();
    //温度
    if (! isnan(t)) {  // check if 'is not a number'

      String dataTtemp2=String(t, 1);//转换成字符串 //温度 保留一位小数
      const char *Ttempstr2 = dataTtemp2.c_str(); //转换为字符数组
      // Paint_DrawNum(223, 23, 338, &Font12, BLACK, WHITE);  //温度
      Paint_DrawString_EN(213, 27, Ttempstr2, &Font16, WHITE, BLACK);//白底黑字//温度
      Paint_DrawString_CN(270, 23,"℃", &Font12CN, BLACK, WHITE);
      
       #if    debuguse  
      Serial.print("Temp *C = "); Serial.println(t);
      #endif    
    } 
    else { 
       #if    debuguse  
      Serial.println("Failed to read temperature");
      #endif
    }

    //湿度
    if (! isnan(h)) {  // check if 'is not a number'
    String dataHtemp2=String(h, 1);//转换成字符串 //湿度 保留一位小数
    const char *Htempstr2 = dataHtemp2.c_str(); //转换为字符数组
      // Paint_DrawNum(223, 40, 666, &Font12, BLACK, WHITE);  //湿度
    Paint_DrawString_EN(213, 43, Htempstr2, &Font16, WHITE, BLACK);//白底黑字 //湿度
    Paint_DrawString_EN(260, 43, "%RH", &Font16, WHITE, BLACK);//白底黑字

      #if    debuguse  
      Serial.print("Hum. % = "); Serial.println(h);
      #endif
    } 
    else { 
      #if    debuguse  
      Serial.println("Failed to read humidity");
      #endif
    }

  // EPD_2IN9_Display(BlackImageAll);
  // DEV_Delay_ms(3000);
    //显示时间
    EPD_2IN9_Init(EPD_2IN9_PART);
    Paint_SelectImage(BlackImageAll);
    PAINT_TIME sPaint_time;
    sPaint_time.Hour = now.hour();
    sPaint_time.Min = now.minute();
    sPaint_time.Sec = now.second();//这个实际不显示

    Paint_ClearWindows(50, 30, 20 + Font48.Width * 7, 30 + Font48.Height, WHITE);
    Paint_DrawTime(50, 30, &sPaint_time, &Font48, WHITE, BLACK);

    EPD_2IN9_Display(BlackImageAll);
    // DEV_Delay_ms(500);//Analog clock 1s


    #if    debuguse  
        printf("epd Goto Sleep...\r\n");
    #endif
    EPD_2IN9_Sleep();
    free(BlackImageAll);
    BlackImageAll = NULL;

    digitalWrite(23, HIGH); //关闭墨水屏  
}

//联网更新时间，并写入RTC
void InitWifiTime()
{
        //设置ESP32工作模式为无线终端模式
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED)
      {
        delay(500);
        #if    debuguse
        Serial.print(".");
        #endif
      }
      Serial.println("WiFi connected!");
      configTime(8 * 3600, 0, NTP1, NTP2, NTP3);
    #if    debuguse
    Serial.println("SET time internet Over!");
    #endif

    delay(1000);
    printLocalTime();

    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
}


//检测闹钟是否到时间，置闹铃标志
void CheckAlarm()
{
  DateTime now = rtc.now();
        //检测闹钟是否到时间
    if(SetAlarOnOffFlag==1)//打开了闹钟 
    {
      
#if    debuguse  
Serial.println("CheckAlarm SetAlarOnOffFlag IS:");
Serial.println(SetAlarOnOffFlag );
#endif   

      if((SetAlarmHour==now.hour())&&(SetAlarmMin==now.minute()))
        {

#if    debuguse  
Serial.println("CheckAlarm OK IS:");
#endif  
          
          if(SetAlarMode == 1)//说明是响一次
          {
            SetAlarOnOffFlag=0;//关闭闹钟
            EEPROM.write(3, SetAlarOnOffFlag); //写入数据
            EEPROM.commit(); //保存更改的数据 
            AlarmStartFlag=1;

#if    debuguse  
Serial.println("CheckAlarm OK  SetAlarMode ONE");
#endif  

          }
          else if(SetAlarMode == 5)//说明是工作日响
          {
              if((now.dayOfTheWeek()!=0)&&(now.dayOfTheWeek()!=6))
              {
                AlarmStartFlag=1;                
              }
          }    
          else if(SetAlarMode == 7)//说明是所有时间都响
          {
             AlarmStartFlag=1;                
          }        
        }  
    } 
}


//墨水屏设置闹钟时间 设置完不休眠epd
void epdOutAlarmSet(int SleepFlag)  //睡眠标志，0不睡眠，1睡眠
{
    DateTime now = rtc.now();

    digitalWrite(23, LOW); //打开墨水屏电源
    DEV_Delay_ms(100);

    #if    debuguse
        printf("EPD_2IN9_test Demo\r\n");
    #endif

    DEV_Module_Init();

    #if    debuguse
        printf("e-Paper Init and Clear...\r\n");
    #endif
    EPD_2IN9_Init(EPD_2IN9_FULL);
    EPD_2IN9_Clear();
    //  DEV_Delay_ms(500);


        //Create a new image cache
    // UBYTE *BlackImage;
    /* you have to edit the startup_stm32fxxx.s file and set a big enough heap size */
    UWORD Imagesize = ((EPD_2IN9_WIDTH % 8 == 0)? (EPD_2IN9_WIDTH / 8 ): (EPD_2IN9_WIDTH / 8 + 1)) * EPD_2IN9_HEIGHT;
    if((BlackImage = (UBYTE *)malloc(Imagesize)) == NULL) {
        #if    debuguse      
        printf("Failed to apply for black memory...\r\n");        
        #endif
        while(1);
    }
    #if    debuguse     
    printf("Paint_NewImage\r\n");
    #endif    
     Paint_NewImage(BlackImage, EPD_2IN9_WIDTH, EPD_2IN9_HEIGHT, 270, WHITE);//旋转了270度显示

    Paint_SelectImage(BlackImage);
    Paint_Clear(WHITE);
    Paint_DrawLine(0, 20, 296, 20, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//上格横线
    Paint_DrawRectangle(210, 20, 296, 108, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);//左边矩形框
    Paint_DrawLine(0, 108, 296, 108, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//下面横线
    Paint_DrawLine(1, 20, 1, 108, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//最左边竖线
    Paint_DrawLine(0, 88, 210, 88, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//中间闹钟横线

    // Paint_DrawLine(68, 106, 88, 106, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//闹钟模式设置显示，在下方画一条线
    // Paint_DrawLine(140, 106, 150, 106, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//闹钟的时设置显示，在下方画一条线
    // Paint_DrawLine(155, 106, 150, 106, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//闹钟的分钟设置显示，在下方画一条线
    

        //显示时间
    EPD_2IN9_Init(EPD_2IN9_PART);
    Paint_SelectImage(BlackImage);
     PAINT_TIME sPaint_time2;
    sPaint_time2.Hour = now.hour();
    sPaint_time2.Min = now.minute();
    sPaint_time2.Sec = now.second();//这个实际不显示

    Paint_ClearWindows(50, 30, 20 + Font48.Width * 7, 30 + Font48.Height, WHITE);
    Paint_DrawTime(50, 30, &sPaint_time2, &Font48, WHITE, BLACK);

//显示当前年月日 星期
    String datatemp1=String(now.year(), DEC);//转换成字符串 显示年
    const char *tempdatastr1 = datatemp1.c_str(); //转换为字符数组
    // Paint_DrawString_EN(0, 0, "2022-09-26", &Font16, WHITE, BLACK);//白底黑字
    Paint_DrawString_EN(0, 2, tempdatastr1 , &Font16, WHITE, BLACK);//白底黑字
    Paint_DrawString_EN(43, 2, "-", &Font16, WHITE, BLACK);//白底黑字

    String datatemp2=String(now.month(), DEC);////转换成字符串 显示月
    const char *tempdatastr2 = datatemp2.c_str(); //转换为字符数组
    Paint_DrawString_EN(53, 2, tempdatastr2, &Font16, WHITE, BLACK);//白底黑字
    Paint_DrawString_EN(73, 2, "-", &Font16, WHITE, BLACK);//白底黑字
    
    String datatemp3=String(now.day(), DEC);//转换成字符串 显示日期
    const char *tempdatastr3 = datatemp3.c_str(); //转换为字符数组
    Paint_DrawString_EN(83, 2, tempdatastr3, &Font16, WHITE, BLACK);//白底黑字

    Paint_DrawString_CN(118, 2,daysOfTheWeek[now.dayOfTheWeek()], &Font12CN, BLACK, WHITE);//显示星期

//    显示电量

    int sensorValue=PowerVolume(analogRead(A0));//gpio 36  
    Paint_DrawString_CN(190, 0,"电量：", &Font12CN, BLACK, WHITE);
    Paint_DrawNum(232, 2, sensorValue, &Font16, BLACK, WHITE);  //电量
    Paint_DrawString_EN(270, 2, "%", &Font16, WHITE, BLACK);//白底黑字

  // //最下格的文字
  //     Paint_DrawString_CN(2, 109,"晴转多云", &Font12CN, BLACK, WHITE);
  //     Paint_DrawString_CN(148, 109,"温度：", &Font12CN, BLACK, WHITE);
  //     Paint_DrawString_EN(194, 109, "30~33", &Font16, WHITE, BLACK);//白底黑字
  //     Paint_DrawString_CN(276, 109,"℃", &Font12CN, BLACK, WHITE);
      
  //中间的闹钟的位置    
  if(SetAlarOnOffFlag==1)  
  {
    Paint_DrawString_CN(2, 88,"闹钟开", &Font12CN, BLACK, WHITE);    
  }
  else 
  {
  Paint_DrawString_CN(2, 88,"闹钟关", &Font12CN, BLACK, WHITE);
  }  

  if(SetAlarMode==1)    
  {
      Paint_DrawString_CN(68, 88,"一次", &Font12CN, BLACK, WHITE);
  }
  else if(SetAlarMode==5)    
  {
      Paint_DrawString_CN(68, 88,"五天模式", &Font12CN, BLACK, WHITE);
  }
  else if(SetAlarMode==7)    
  {
      Paint_DrawString_CN(68, 88,"七天模式", &Font12CN, BLACK, WHITE);  
  }

    //显示设定的闹钟时间    
    PAINT_TIME sPaint_alar_time2;
    sPaint_alar_time2.Hour = SetAlarmHour;
    sPaint_alar_time2.Min = SetAlarmMin;
    sPaint_alar_time2.Sec = 0;//这个实际不显示  
    Paint_ClearWindows(140, 90, 30 + Font16.Width * 7, 88 + Font16.Height, WHITE);
    Paint_DrawTime(140, 90, &sPaint_alar_time2, &Font16, WHITE, BLACK);

  // Paint_DrawString_EN(148, 88, "07:10", &Font16, WHITE, BLACK);//白底黑字
        
//温度、湿度和大气压
    float t = sht31.readTemperature();
    float h = sht31.readHumidity();
    //温度
    if (! isnan(t)) {  // check if 'is not a number'

      String dataTtemp2=String(t, 1);//转换成字符串 //温度 保留一位小数
      const char *Ttempstr2 = dataTtemp2.c_str(); //转换为字符数组
      // Paint_DrawNum(223, 23, 338, &Font12, BLACK, WHITE);  //温度
      Paint_DrawString_EN(213, 27, Ttempstr2, &Font16, WHITE, BLACK);//白底黑字//温度
      Paint_DrawString_CN(270, 23,"℃", &Font12CN, BLACK, WHITE);
      
       #if    debuguse  
      Serial.print("Temp *C = "); Serial.println(t);
      #endif    
    } 
    else { 
       #if    debuguse  
      Serial.println("Failed to read temperature");
      #endif
    }

    //湿度
    if (! isnan(h)) {  // check if 'is not a number'
    String dataHtemp2=String(h, 1);//转换成字符串 //湿度 保留一位小数
    const char *Htempstr2 = dataHtemp2.c_str(); //转换为字符数组

      // Paint_DrawNum(223, 40, 666, &Font12, BLACK, WHITE);  //湿度
    Paint_DrawString_EN(213, 43, Htempstr2, &Font16, WHITE, BLACK);//白底黑字 //湿度
    Paint_DrawString_EN(260, 43, "%RH", &Font16, WHITE, BLACK);//白底黑字

      #if    debuguse  
      Serial.print("Hum. % = "); Serial.println(h);
      #endif
    } 
    else { 
      #if    debuguse  
      Serial.println("Failed to read humidity");
      #endif
    }

  // EPD_2IN9_Display(BlackImage);
  // DEV_Delay_ms(3000);
    //显示时间
    EPD_2IN9_Init(EPD_2IN9_PART);
    Paint_SelectImage(BlackImage);
    PAINT_TIME sPaint_time;
    sPaint_time.Hour = now.hour();
    sPaint_time.Min = now.minute();
    sPaint_time.Sec = now.second();//这个实际不显示

    Paint_ClearWindows(50, 30, 20 + Font48.Width * 7, 30 + Font48.Height, WHITE);
    Paint_DrawTime(50, 30, &sPaint_time, &Font48, WHITE, BLACK);

    EPD_2IN9_Display(BlackImage);
    // DEV_Delay_ms(500);//Analog clock 1s


    if(SleepFlag==1)
    {
          #if    debuguse  
            printf("epd Goto Sleep...\r\n");
        #endif
        EPD_2IN9_Sleep();
        free(BlackImage);
        BlackImage = NULL;

        digitalWrite(23, HIGH); //关闭墨水屏  
    }


}




void epdOutAlarmSetChange(int Postion)  //下划线选择设置  1为闹钟模式下面加下划线，2为闹钟时间的时加下划线，3为闹钟时间的分加下划线
{
    // UBYTE *BlackImage;
  
    EPD_2IN9_Init(EPD_2IN9_PART);
    Paint_SelectImage(BlackImage);

    Paint_ClearWindows(67, 105, 185, 106, WHITE);//清空原来的线

    if(Postion==1) 
    {
      Paint_DrawLine(68, 106, 130, 106, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//闹钟模式设置显示，在下方画一条线
    }
    else if(Postion==2) 
    {
      Paint_DrawLine(142, 106, 160, 106, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//闹钟的时设置显示，在下方画一条线
    }
    else if(Postion==3) 
    {
      Paint_DrawLine(167, 106, 187, 106, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);//闹钟的分钟设置显示，在下方画一条线
    }

    EPD_2IN9_Display(BlackImage);
    // DEV_Delay_ms(500);//Analog clock 1s

}

void epdOutAlarmSetModeChange()  //闹钟模式选择显示，一次，5天制，7天制显示
{

    EPD_2IN9_Init(EPD_2IN9_PART);
    Paint_SelectImage(BlackImage);

    Paint_ClearWindows(68, 88, 140, 104, WHITE);//清空原来字
  if(SetAlarMode==1)    
  {
      Paint_DrawString_CN(68, 88,"一次", &Font12CN, BLACK, WHITE);
  }
  else if(SetAlarMode==5)    
  {
      Paint_DrawString_CN(68, 88,"五天模式", &Font12CN, BLACK, WHITE);
  }
  else if(SetAlarMode==7)    
  {
      Paint_DrawString_CN(68, 88,"七天模式", &Font12CN, BLACK, WHITE);  
  }

    EPD_2IN9_Display(BlackImage);
    // DEV_Delay_ms(500);//Analog clock 1s

}

void epdOutAlarmSetHourMinChange()  //闹钟时间设置选择显示 同时显示时分
{

    // UBYTE *BlackImage;
    EPD_2IN9_Init(EPD_2IN9_PART);
    Paint_SelectImage(BlackImage);

    Paint_ClearWindows(140, 88, 190, 104, WHITE);//清空原来字

    //显示设定的闹钟时间    
    PAINT_TIME sPaint_alar_time2;
    sPaint_alar_time2.Hour = SetAlarmHour;
    sPaint_alar_time2.Min = SetAlarmMin;
    sPaint_alar_time2.Sec = 0;//这个实际不显示  
    Paint_ClearWindows(140, 90, 30 + Font16.Width * 7, 88 + Font16.Height, WHITE); //清空原来字
    Paint_DrawTime(140, 90, &sPaint_alar_time2, &Font16, WHITE, BLACK);

    EPD_2IN9_Display(BlackImage);
    // DEV_Delay_ms(500);//Analog clock 1s

    // free(BlackImage);
    // BlackImage = NULL;
}



/*
Method to print the GPIO that triggered the wakeup
*/
void print_GPIO_wake_up(){
  uint64_t GPIO_reason = esp_sleep_get_ext1_wakeup_status();
  Serial.print("GPIO that triggered the wake up: GPIO ");
  Serial.println((log(GPIO_reason))/log(2), 0);
  Serial.println("UINT IS:");
  Serial.println(GPIO_reason);  
}














/* Entry point ----------------------------------------------------------------*/
void setup()
{

  Serial.begin(115200);

  
  pinMode(4, INPUT);//初始化4号管脚为输入，button1 闹钟暂停和背光按钮  RTC-GPIO-10
  pinMode(2, INPUT);//初始化2号管脚为输入，button2 闹钟闹钟开关按钮   RTC-GPIO-12
  pinMode(12, INPUT);//初始化12号管脚为输入，button3 选择   RTC-GPIO-15
  pinMode(35, INPUT);//初始化35号管脚为输入，button4 +  RTC-GPIO-5
  pinMode(32, INPUT);//初始化32号管脚为输入，button5 -  RTC-GPIO-9
  pinMode(33, INPUT);//初始化33号管脚为输入，button6 确定  RTC-GPIO-8


  pinMode(23, OUTPUT);//初始化23号管脚为输出，墨水屏供电控制
  pinMode(5, OUTPUT);//初始化5号管脚为输出，蜂鸣器控制
  pinMode(18, OUTPUT);//初始化18号管脚为输出，背光LED控制

  
//初始化输出管脚
  digitalWrite(23, HIGH); //关闭墨水屏
  digitalWrite(5, LOW);//关闭蜂鸣器
  digitalWrite(18, LOW);//关闭LED背光

  // button1Flag= digitalRead(4);//button1 闹钟暂停和背光按钮
  // button2Flag= digitalRead(2);//button2 闹钟闹钟开关按钮 
  // button3Flag= digitalRead(12);//butto3 选择
  // button4Flag= digitalRead(35);//button4 + 
  // button5Flag= digitalRead(32);//button5 - 
  // button6Flag= digitalRead(33);//button6 确定

  //初始化DS3232的RTC模块
      if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }

  //  初始化温湿度模块
    if (! sht31.begin(0x44)) {   // Set to 0x45 for alternate i2c addr
    Serial.println("Couldn't find SHT31");
    while (1) delay(1);
  }


  analogSetPinAttenuation(A0,ADC_0db); //测试范围100mv~950mv 参考电压1.1v

  EEPROM.begin(10); //申请10个字节的EEPROM存储空间，存储闹钟的时间、模式和是否开关闹钟的状态

/////////////////////////////////////////////////////////////////////////////////
//读出存储的闹钟时间、模式和开关闹钟情况
 SetAlarmHour = EEPROM.read(0); //读数据，闹钟设置的小时
 SetAlarmMin = EEPROM.read(1); //读数据，闹钟设置的分钟
 SetAlarMode = EEPROM.read(2); //读数据，闹钟设置的模式
 SetAlarOnOffFlag = EEPROM.read(3); //读数据，闹钟设置的开关


if(SetAlarmHour>25)//说明小时时间不对
{
  EEPROM.write(0, 12); //写入数据
  EEPROM.commit(); //保存更改的数据 
}
if(SetAlarmMin>60)//说明分钟时间不对
{
  EEPROM.write(1, 00); //写入数据
  EEPROM.commit(); //保存更改的数据 
}
if((SetAlarMode==1)||(SetAlarMode==5)||(SetAlarMode==7))//说明模式设置不对，响一次，5天响，7天响
{
  ;
}
else 
{
  
  EEPROM.write(2, 1); //写入数据
  EEPROM.commit(); //保存更改的数据
}
if((SetAlarOnOffFlag==0)||(SetAlarOnOffFlag==1))//说明开关设置不对，设置为关
{
  ;
}
else
{
  EEPROM.write(3, 0); //写入数据
  EEPROM.commit(); //保存更改的数据 
}

 SetAlarmHour = EEPROM.read(0); //读数据，闹钟设置的小时
 SetAlarmMin = EEPROM.read(1); //读数据，闹钟设置的分钟
 SetAlarMode = EEPROM.read(2); //读数据，闹钟设置的模式  响一次，5天响，7天响
 SetAlarOnOffFlag = EEPROM.read(3); //读数据，闹钟设置的开关 0是关了闹钟，1是开闹钟


//以上是读出闹钟相关参数
////////////////////////////////////////////////////////////////////////////////


    // digitalWrite(23, LOW); //打开墨水屏电源
    // DEV_Delay_ms(100);

    print_wakeup_reason();//得到苏醒的原因
}


/* The main loop -------------------------------------------------------------*/
int DelayCount=0;
int BuzzerGpioFlag=0;//管脚状态
int SetFlag=0;//选择第几项记录

int AlarmDelayCountStop=0;//在没有人关闭闹钟的情况下计数，响一分钟后自动停止
void loop()
{
  
  if(WakeFlag==6)//说明是第一次上电启动的，初始化EPD和时钟
  {
    
    InitWifiTime();//联网对时
    epdOut();   //墨水屏的显示 
    CheckAlarm();//检测闹钟是否到时间，置闹铃标志
    AlarmDelayCountStop=0;//清一下计数器
   
  }

  else if(WakeFlag==3)//说明是定时器苏醒，要更新一下时间
  {
    epdOut();   //墨水屏的显示 
    CheckAlarm();  //检测闹钟是否到时间，置闹铃标志
    AlarmDelayCountStop=0;//清一下计数器 
      
  }

  else if(WakeFlag==2)  //外部管脚触发唤醒
  {
          // if(esp_sleep_get_ext1_wakeup_status()==16)//说明是button1按钮
    if(log(esp_sleep_get_ext1_wakeup_status())/log(2)==4)//说明是button1按钮 停止闹钟或者打开背光
    {
 
      if(AlarmStartFlag==1)//说明闹钟在响
      {
        AlarmStartFlag=0;
      }   
      else
      {
        digitalWrite(18, HIGH);//打开LED背光   
        while(digitalRead(4));
        digitalWrite(18, LOW);//关闭LED背光
      }
    }
    if(log(esp_sleep_get_ext1_wakeup_status())/log(2)==2)//开关闹钟选项的按键
    {
      if(SetAlarOnOffFlag==0)//说明开关设置为关，设置为开
      {
        EEPROM.write(3, 1); //写入数据
        EEPROM.commit(); //保存更改的数据 
        SetAlarOnOffFlag=1;
      }
      else if(SetAlarOnOffFlag==1)//说明开关设置开，设置为关
      {
        EEPROM.write(3, 0); //写入数据
        EEPROM.commit(); //保存更改的数据 
        SetAlarOnOffFlag=0;
      }
      epdOutAlarmSet(1);  //墨水屏的显示 休眠和清除显存
    }
     if(log(esp_sleep_get_ext1_wakeup_status())/log(2)==12)//设置选择按钮
    {
      SetFlag=1;//选择闹钟模式选项

      //读出存储的闹钟时间、模式和开关闹钟情况
      SetAlarmHour = EEPROM.read(0); //读数据，闹钟设置的小时
      SetAlarmMin = EEPROM.read(1); //读数据，闹钟设置的分钟
      SetAlarMode = EEPROM.read(2); //读数据，闹钟设置的模式
      SetAlarOnOffFlag = EEPROM.read(3); //读数据，闹钟设置的开关

      epdOutAlarmSet(0);  //墨水屏的显示 不休眠和清楚显存//刷新epd不休眠
      epdOutAlarmSetChange(SetFlag);//显示下划线
      for(uint16_t nn=0;nn<3000;nn++)//延时30S做为设置等待，如果有按键操作就再延时30S
      {     
        if(digitalRead(12))//选择按键
        {
          nn=0;//清一下计数器，再延时30S
          if(SetFlag<3) SetFlag++;
          else SetFlag=1;//到第一项
          epdOutAlarmSetChange(SetFlag);//加下划线 
        }   
        else if(digitalRead(35))//+加号按键
        {
          nn=0;//清一下计数器，再延时30S
          if(SetFlag==1)//说明设置闹钟模式
          {
            if(SetAlarMode==1)
            {
              SetAlarMode=5;
            }   
            else if(SetAlarMode==5)
            {
              SetAlarMode=7;
            }          
            else if(SetAlarMode==7)
            {
              SetAlarMode=1;
            }    
            epdOutAlarmSetModeChange();//显示
          }
          else if(SetFlag==2)//说明是设置闹钟时间的时
          {
            if(SetAlarmHour<24)
            {
              SetAlarmHour++;
              epdOutAlarmSetHourMinChange();  
            } 
            else if(SetAlarmHour==24)                                           
            {
              SetAlarmHour=0;
              epdOutAlarmSetHourMinChange();  
            }     
        }
          else if(SetFlag==3)//说明是设置闹钟时间的分
          {
            if(SetAlarmMin<59)
            {
              SetAlarmMin++;
              epdOutAlarmSetHourMinChange();  
            } 
            else if(SetAlarmMin==59)                   
            {
              SetAlarmMin=0;
              epdOutAlarmSetHourMinChange();  
            }
          }
          
        }  
        else if(digitalRead(32))//-加号按键
        {

          nn=0;//清一下计数器，再延时30S
          if(SetFlag==1)//说明设置闹钟模式
          {
            if(SetAlarOnOffFlag==1)
            {
              SetAlarOnOffFlag=7;
            }   
            else if(SetAlarOnOffFlag==7)
            {
              SetAlarOnOffFlag=5;
            }          
            else if(SetAlarOnOffFlag==5)
            {
              SetAlarOnOffFlag=1;
            }    
            epdOutAlarmSetModeChange();//显示
          }
          else if(SetFlag==2)//说明是设置闹钟时间的时
          {
            if(SetAlarmHour>0)
            {
              SetAlarmHour--;
              epdOutAlarmSetHourMinChange();  
            }   
            else if(SetAlarmHour==0)                                           
            {
              SetAlarmHour=24;
              epdOutAlarmSetHourMinChange();  
            }        
          }
          else if(SetFlag==3)//说明是设置闹钟时间的分
          {
            if(SetAlarmMin>0)
            {
              SetAlarmMin--;
              epdOutAlarmSetHourMinChange();  
            }   
            else if(SetAlarmMin==0)                   
            {
              SetAlarmMin=59;
              epdOutAlarmSetHourMinChange();  
            }     
          }
        }  
        else if(digitalRead(33))//确认按键  写入数据并退出
        {
          nn=0;//清一下计数器，再延时30S
          EEPROM.write(0, SetAlarmHour); //写入数据，闹钟设置的小时
          EEPROM.write(1, SetAlarmMin); //写入数据，闹钟设置的分钟
          EEPROM.write(2, SetAlarMode); //写入数据，闹钟设置的模式
          EEPROM.write(3, SetAlarOnOffFlag); //写入数据，闹钟设置的开关
          EEPROM.commit(); //保存更改的数据 

          epdOutAlarmSet(1);//墨水屏彻底显示一下  

          // //设置外部管脚唤醒
          esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); //设置休眠时间
          esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

          #if    debuguse  
          Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
          " Seconds");
          #endif

          #if    debuguse  
          Serial.println("This will never be printed");
          #endif    
          Serial.flush(); 
          esp_deep_sleep_start();//开始休眠           
        }        

          
        delay(10);//延时10ms
      }
      epdOut();   //墨水屏彻底显示一下 
    }


    // print_GPIO_wake_up();//查找是哪个按钮被按下

    // //设置外部管脚唤醒

    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); //设置休眠时间
    esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

    #if    debuguse  
    Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
    " Seconds");
    #endif

    #if    debuguse  
    Serial.println("This will never be printed");
     #endif    
    Serial.flush(); 
    esp_deep_sleep_start();//开始休眠    
  }  

  WakeFlag=0;//复位以下

    // print_GPIO_wake_up();//查找是哪个按钮被按下


  if(AlarmStartFlag==0)//说明闹钟没有响，可以进行休眠
  {

    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); //设置休眠时间
    // //设置外部管脚唤醒
    esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);
    #if    debuguse  
    Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
    " Seconds");
    #endif

    #if    debuguse  
    Serial.println("This will never be printed");
    #endif    
    Serial.flush(); 
    esp_deep_sleep_start();//开始休眠

  }

  

    button1Flag= digitalRead(4);//button1 闹钟暂停和背光按钮
    button2Flag= digitalRead(2);//button2 闹钟闹钟开关按钮 
    button3Flag= digitalRead(12);//butto3 选择
    button4Flag= digitalRead(35);//button4 + 
    button5Flag= digitalRead(32);//button5 - 
    button6Flag= digitalRead(33);//button6 确定

  #if    debuguse  
      Serial.println("No sleep");
      Serial.println("AlarmStartFlag IS:");
      Serial.println(AlarmStartFlag);
    #endif

    if(button1Flag==1)//说明是button1被按下，暂停闹钟
    {
      if(AlarmStartFlag==1)//说明闹钟在响
      {
        AlarmStartFlag=0;
        if(SetAlarMode==1) //显示闹钟关的字
        {
          digitalWrite(5, LOW);//关闭蜂鸣器
          epdOut(); 
        }
       
      }      
    } 
    


    //响蜂鸣器
    if(AlarmStartFlag==1)//说明闹钟在响       
    {
      DelayCount++;
      if(DelayCount>20)      
      {
#if    debuguse  
Serial.println("Alarm Sound");
#endif          
        DelayCount=0;
        if(BuzzerGpioFlag==0)      
        {
          BuzzerGpioFlag=1;
          digitalWrite(5, HIGH);//打开蜂鸣器
        }
        else 
        {
          BuzzerGpioFlag=0;
          digitalWrite(5, LOW);//关闭蜂鸣器
        }  
      }
    }  
    else digitalWrite(5, LOW);//关闭蜂鸣器

//计数如果没有人停止那种到1.5分钟后就自动停止
    AlarmDelayCountStop++;
    if(AlarmDelayCountStop>9000)
    {
      AlarmDelayCountStop=0;//清计数器
      AlarmStartFlag=0;//关闭闹钟
      if(SetAlarMode==1) //说明只响一次，显示闹钟关的字
      {
        SetAlarOnOffFlag=0;//关闭闹钟
        EEPROM.write(3, SetAlarOnOffFlag); //写入数据
        EEPROM.commit(); //保存更改的数据 
        
        digitalWrite(5, LOW);//关闭蜂鸣器
        epdOut(); 
      }
    }
    delay(10);//延时10ms
     



}
